package com.itbour.common.util;

import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import org.apache.tomcat.util.codec.binary.Base64;

import com.itbour.def.SystemConf;
import com.itbour.dto.com.OSSTokenInfoDto;


public class OSSUtil {
	
	public static final String TYPE_IMAGE = "image";
	public static final String TYPE_AUDIO = "audio";
	public static final String TYPE_VIDEO = "video";
	public static final String TYPE_FONT = "font";
	
	private static final String ACCESS_KEY_ID = SystemConf.getOssAccessKeyId();
    private static final String ACCESS_KEY_SECRET = SystemConf.getOssAccessKeySecret();
    private static final String BUCKET_DOMAIN = SystemConf.getOssDomain();
    private static final String END_POINT = SystemConf.getOssRegion();
    
    private static Mac macInstance;
    private static final Object LOCK = new Object();
    
    /* The default encoding. */
    private static final String DEFAULT_ENCODING = "UTF-8";
    /* Signature method. */
    private static final String ALGORITHM = "HmacSHA1";

    // expiration: 有效时长（单位秒）
	public OSSTokenInfoDto getToken(int validTime) {
		// Create a new OSSClient instance
		// OSSClient client = new OSSClient(END_POINT, ACCESS_KEY_ID, ACCESS_KEY_SECRET);
		
		// 有效时间
		int vt = validTime;
		if (vt <= 10){
			vt = 3600;// 默认3600秒
		}
		// 期限日时
		Calendar time = Calendar.getInstance();
        time.add(Calendar.SECOND, vt);
        // UTC日期格式
        Date dt = time.getTime();
        SimpleDateFormat utcFmt = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
        String strDeadline = utcFmt.format(dt);
        
        // content大小
        long maxLen = 1024*1024*100;

        // policy
        String policyTxt = "{\"expiration\":\"" + strDeadline +"\","
        		+ "\"conditions\":[["
        		+ "\"content-length-range\",0," + maxLen + "]]}";

        String policyB64 = "";
        String signature = "";
        try {
        	policyB64 = toBase64String(policyTxt.getBytes(DEFAULT_ENCODING));
        	signature = computeSignature(ACCESS_KEY_SECRET, policyB64);
        }
        catch(UnsupportedEncodingException ex) {
            throw new RuntimeException("Unsupported algorithm: " + DEFAULT_ENCODING, ex);
        }

		// 返回值
        OSSTokenInfoDto ret = new OSSTokenInfoDto();
        ret.setExpire(dt.getTime());
        ret.setPolicy(policyTxt);
        ret.setPolicyBase64(policyB64);
        ret.setSignature(signature);
        ret.setAccessKeyId(ACCESS_KEY_ID);
        ret.setUploadHost(BUCKET_DOMAIN);
		return ret;
	}
	
	public String computeSignature(String key, String data) {
        try {
            byte[] signData = sign(key.getBytes(DEFAULT_ENCODING), data.getBytes(DEFAULT_ENCODING));
            return toBase64String(signData);
        }
        catch(UnsupportedEncodingException ex) {
            throw new RuntimeException("Unsupported algorithm: " + DEFAULT_ENCODING, ex);
        }
    }

	private String toBase64String(byte[] binaryData) {
		String ret =  new String(Base64.encodeBase64(binaryData));
        return ret;
    }

    private byte[] sign(byte[] key, byte[] data) {
        try {
            // Because Mac.getInstance(String) calls a synchronized method, it could block on 
            // invoked concurrently, so use prototype pattern to improve perf.
            if (macInstance == null) {
                synchronized (LOCK) {
                    if (macInstance == null) {
                        macInstance = Mac.getInstance(ALGORITHM);
                    }
                }
            }

            Mac mac = null;
            try {
                mac = (Mac)macInstance.clone();
            } catch (CloneNotSupportedException e) {
                // If it is not clonable, create a new one.
                mac = Mac.getInstance(ALGORITHM);
            }
            mac.init(new SecretKeySpec(key, ALGORITHM));
            return mac.doFinal(data);
        }
        catch(NoSuchAlgorithmException ex) {
            throw new RuntimeException("Unsupported algorithm: " + ALGORITHM, ex);
        }
        catch(InvalidKeyException ex) {
            throw new RuntimeException("Invalid key: " + key, ex);
        }
    }
}

//########################### JS code sample ##################################
//https://bbs.aliyun.com/read/262307.html?spm=5176.bbsl211.0.0.I0pTVy
//var policyText = {
//	    "expiration": "2020-01-01T12:00:00.000Z", //设置该Policy的失效时间，超过这个失效时间之后，就没有办法通过这个policy上传文件了
//	    "conditions": [
//	        ["content-length-range", 0, 104857600] // 设置上传文件的大小限制
//	    ]
//	};
//var policyJsonStr = JSON.stringify(policyText);
//var policyBase64 = Base64.encode(policyJsonStr);
//var message = policyBase64;
//var bytes = Crypto.HMAC(Crypto.SHA1, message, accesskey, { asBytes: true });
//var signature = Crypto.util.bytesToBase64(bytes);
//########################### JS code sample ##################################
